#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
#include "protocol.h"
#include "frame_driver.h"
#include "common_driver.h"
#include "system.h"
#include "memory.h"

/****************************************************
@function:发送通用命令(不携带命令内容值)
@param:
    interrupt:真-中断场景,假-非中断场景
    buf：发送缓冲区
    CommandType:命令类型
    CodeType：命令编码
@return:void
@note:
****************************************************/
void Protocol_CommandSend_General_NullValue(bool interrupt,uint8_t *buf,uint8_t CommandType,uint8_t CodeType)
{
    uint32_t pos = 0;

    if((buf == NULL) || (CommandType >= eCommandType_Num))return;
    *(buf + pos++) = dFrame_IdentifyA;
    *(buf + pos++) = dFrame_IdentifyA_Invert;
    *(buf + pos++) = 0;
    *(buf + pos++) = 0;

    *(buf + pos++) = System_BoardAddressGet();//发送设备地址
    *(buf + pos++) = eDeviceAddress_Master;//接收设备地址
    *(buf + pos++) = CommandType;//命令类型
    *(buf + pos++) = CodeType;//代码

    *(buf + 2) = dDataLength_MSB(pos-4+1);//帧数据字节数高8位
    *(buf + 3) = dDataLength_LSB(pos-4+1);//帧数据字节数低8位
    *(buf + pos++) = frame_ChecksumGet(buf,pos);
    Protocol_Transfer(interrupt,buf,pos);
}

/****************************************************
@function:发送通用命令(只携带一个命令内容值)
@param:
    interrupt:真-中断场景,假-非中断场景
    buf：发送缓冲区
    CommandType:命令类型
    CodeType：命令编码
    value:值
@return:void
@note:
****************************************************/
void Protocol_CommandSend_General_OneValue(bool interrupt,uint8_t *buf,uint8_t CommandType,uint8_t CodeType,uint8_t value)
{
    uint32_t pos = 0;

    if((buf == NULL) || (CommandType >= eCommandType_Num))return;
    *(buf + pos++) = dFrame_IdentifyA;
    *(buf + pos++) = dFrame_IdentifyA_Invert;
    *(buf + pos++) = 0;
    *(buf + pos++) = 0;

    *(buf + pos++) = System_BoardAddressGet();//发送设备地址
    *(buf + pos++) = eDeviceAddress_Master;//接收设备地址
    *(buf + pos++) = CommandType;//命令类型
    *(buf + pos++) = CodeType;//代码
    *(buf + pos++) = value;

    *(buf + 2) = dDataLength_MSB(pos-4+1);//帧数据字节数高8位
    *(buf + 3) = dDataLength_LSB(pos-4+1);//帧数据字节数低8位
    *(buf + pos++) = frame_ChecksumGet(buf,pos);
    Protocol_Transfer(interrupt,buf,pos);
}

/****************************************************
@function:发送采样应答命令
@param:
    interrupt:真-中断场景,假-非中断场景
    buf：发送缓冲区
    temperature:温度,单位℃
    concentration:浓度，单位待定与校准数据文本一致
    VoltageTemperature:温度检测电压,单位V
    VoltageHydrogen:氢气检测电压,单位V
@return:void
@note:内容=16字节=采样数据;温度+浓度+温度检测电压+氢气检测电压,参数均float(4个字节)
****************************************************/
void Protocol_CommandSend_Device_Sample_Ack(bool interrupt,uint8_t *buf,float temperature,float concentration,float VoltageTemperature,float VoltageHydrogen)
{
    uint32_t pos = 0;
    Common_Convert_float_Parameter_UnionDef vfloat;

    if(buf == NULL)return;
    *(buf + pos++) = dFrame_IdentifyA;
    *(buf + pos++) = dFrame_IdentifyA_Invert;
    *(buf + pos++) = 0;
    *(buf + pos++) = 0;

    *(buf + pos++) = System_BoardAddressGet();//发送设备地址
    *(buf + pos++) = eDeviceAddress_Master;//接收设备地址
    *(buf + pos++) = eCommandType_Device;
    *(buf + pos++) = eCodeType_Device_Sample_Ack;

    vfloat.value = temperature;
    *(buf + pos++) = vfloat.memory.byte1;
    *(buf + pos++) = vfloat.memory.byte2;
    *(buf + pos++) = vfloat.memory.byte3;
    *(buf + pos++) = vfloat.memory.byte4;

    vfloat.value = concentration;
    *(buf + pos++) = vfloat.memory.byte1;
    *(buf + pos++) = vfloat.memory.byte2;
    *(buf + pos++) = vfloat.memory.byte3;
    *(buf + pos++) = vfloat.memory.byte4;

    vfloat.value = VoltageTemperature;
    *(buf + pos++) = vfloat.memory.byte1;
    *(buf + pos++) = vfloat.memory.byte2;
    *(buf + pos++) = vfloat.memory.byte3;
    *(buf + pos++) = vfloat.memory.byte4;

    vfloat.value = VoltageHydrogen;
    *(buf + pos++) = vfloat.memory.byte1;
    *(buf + pos++) = vfloat.memory.byte2;
    *(buf + pos++) = vfloat.memory.byte3;
    *(buf + pos++) = vfloat.memory.byte4;

    *(buf + 2) = dDataLength_MSB(pos-4+1);//帧数据字节数高8位
    *(buf + 3) = dDataLength_LSB(pos-4+1);//帧数据字节数低8位
    *(buf + pos++) = frame_ChecksumGet(buf,pos);
    Protocol_Transfer(interrupt,buf,pos);
}

/****************************************************
@function:发送文件
@param:
    interrupt:真-中断场景,假-非中断场景
    buf：发送缓冲区
    BufferSize:缓冲区字节数
    object:文件传输对象,见Memory_FileObject_EnumDef
@return:void
@note:
****************************************************/
void Protocol_CommandSend_FileTransmit(bool interrupt,uint8_t *buf,uint32_t BufferSize,uint8_t object)
{
    if((buf == NULL) || (BufferSize == 0))return;
    uint32_t pos = 0;
    uint16_t LineNumber = 0,ContentSize = 0,i = 0,FrameLineNumberMax = 0,FrameLineNumber = 0;
    extern osMessageQId nQueueTransferHandle;
    UBaseType_t QueueResidueSize = 0;

    //处理文件数据空或者文件对象参数错误
    LineNumber = Memory_FileLineNumber_Read((Memory_FileObject_EnumDef )object);
    if((LineNumber == 0) || (object >= eMemory_FileObject_Num)){Protocol_CommandSend_General_OneValue(interrupt,buf,eCommandType_Device,eCodeType_Device_FileTransmit_DataAck,((object >= eMemory_FileObject_Num)?1:2));return;}

    ContentSize = Memory_FileFormatContentSize_Get((Memory_FileObject_EnumDef )object);
    FrameLineNumberMax = (BufferSize - 14)/ContentSize;//帧最大携带数据长度

    //1、传输文件数据内容
    for(i = 0,pos = 0;i < LineNumber;)
    {
        FrameLineNumber = ((LineNumber - i) > FrameLineNumberMax)?FrameLineNumberMax:(LineNumber - i);//计算帧发送多少行数据
        pos = 0;
        *(buf + pos++) = dFrame_IdentifyA;
        *(buf + pos++) = dFrame_IdentifyA_Invert;
        *(buf + pos++) = 0;
        *(buf + pos++) = 0;

        *(buf + pos++) = System_BoardAddressGet();//发送设备地址
        *(buf + pos++) = eDeviceAddress_Master;//接收设备地址
        *(buf + pos++) = eCommandType_Device;
        *(buf + pos++) = eCodeType_Device_FileTransmit_Data;

        *(buf + pos++) = object;//文件对象
        *(buf + pos++) = dDataLength_MSB(i);//行索引值,起始值0;高8位
        *(buf + pos++) = dDataLength_LSB(i);//行索引值,低8位
        *(buf + pos++) = dDataLength_MSB(FrameLineNumber);//帧携带行数高8位
        *(buf + pos++) = dDataLength_LSB(FrameLineNumber);//帧携带行数低8位

        //复制行数据
        Memory_FileContent_Read((Memory_FileObject_EnumDef )object,i,(void *)(buf + pos),FrameLineNumber);
        pos += FrameLineNumber * ContentSize;

        *(buf + 2) = dDataLength_MSB(pos-4+1);//帧数据字节数高8位
        *(buf + 3) = dDataLength_LSB(pos-4+1);//帧数据字节数低8位
        *(buf + pos++) = frame_ChecksumGet(buf,pos);

        while(1)
        {
            QueueResidueSize = uxQueueSpacesAvailable(nQueueTransferHandle);
            if(QueueResidueSize > pos)break;
            osDelay(1);
        }

        Protocol_Transfer(interrupt,buf,pos);
        i += FrameLineNumber;
    }

    //2、传输文件结束帧
    {
        pos = 0;
        *(buf + pos++) = dFrame_IdentifyA;
        *(buf + pos++) = dFrame_IdentifyA_Invert;
        *(buf + pos++) = 0;
        *(buf + pos++) = 0;

        *(buf + pos++) = System_BoardAddressGet();//发送设备地址
        *(buf + pos++) = eDeviceAddress_Master;//接收设备地址
        *(buf + pos++) = eCommandType_Device;
        *(buf + pos++) = eCodeType_Device_FileTransmit_Finish;

        *(buf + pos++) = object;//文件对象
        *(buf + pos++) = dDataLength_MSB(LineNumber);//文件行数高8位
        *(buf + pos++) = dDataLength_LSB(LineNumber);//文件行数低8位


        *(buf + 2) = dDataLength_MSB(pos-4+1);//帧数据字节数高8位
        *(buf + 3) = dDataLength_LSB(pos-4+1);//帧数据字节数低8位
        *(buf + pos++) = frame_ChecksumGet(buf,pos);

        while(1)
        {
            QueueResidueSize = uxQueueSpacesAvailable(nQueueTransferHandle);
            if(QueueResidueSize > pos)break;
            osDelay(1);
        }
        Protocol_Transfer(interrupt,buf,pos);
    }
}

/****************************************************
@function:模拟主机发送通用命令(不携带命令内容值)
@param:
    interrupt:真-中断场景,假-非中断场景
    buf：发送缓冲区
    CommandType:命令类型
    CodeType：命令编码
@return:void
@note:
****************************************************/
void Protocol_CommandSend_General_NullValue_Master(bool interrupt,uint8_t *buf,uint8_t CommandType,uint8_t CodeType)
{
    uint32_t pos = 0;

    if((buf == NULL) || (CommandType >= eCommandType_Num))return;
    *(buf + pos++) = dFrame_IdentifyA;
    *(buf + pos++) = dFrame_IdentifyA_Invert;
    *(buf + pos++) = 0;
    *(buf + pos++) = 0;

    *(buf + pos++) = eDeviceAddress_Master;//发送设备地址
    *(buf + pos++) = System_BoardAddressGet();//接收设备地址
    *(buf + pos++) = CommandType;//命令类型
    *(buf + pos++) = CodeType;//代码

    *(buf + 2) = dDataLength_MSB(pos-4+1);//帧数据字节数高8位
    *(buf + 3) = dDataLength_LSB(pos-4+1);//帧数据字节数低8位
    *(buf + pos++) = frame_ChecksumGet(buf,pos);
    Protocol_Transfer(interrupt,buf,pos);
}
